import { constantRoutes } from '@/router'
import { getMenu } from '@/api/login'
import Layout from '@/layout/index'


// 遍历传递过来的路由数组，将 component 字符串对应的组件，进行注册
// asyncRouterMap : 要注册的路由对象数组
// 这是一个递归注册子路由的函数 ！！！！！！！！
function filterAsyncRouter(asyncRouterMap) {

  try {
    // [数组].filter() ：数组过滤器方法，参数为一个函数，返回经过处理的数组
    // 函数可以接收两个参数：当前元素的值，当前元素的索引（可选）
    return asyncRouterMap.filter(
      route => { // 这里是获取到数组中的一个路由对象
        // 判断是否存在组件 component 需要注册
        if (route.component) {
          // 判断组件是否为 Layout组件，如果是，就进行特殊处理
          if (route.component === 'Layout') {
            // 直接给路由对象，赋值我们引入的 Layout 对象
            // 相当于给对象 route 设置属性 component: Layout 具体可以参考路由
            route.component = Layout
          } else {
            // 如果不是 Layout 组件，那么传递过来的对象中，则是保存了具体的组件路径，这里先保存路径，用于后面的拼接路径
            const component = route.component
            // 这里是使用异步函数，只有被调用才会进行加载，我们使用这个函数，进行路由拼接并注册
            route.component = resolve => require(['@/views' + component + '.vue'], resolve)
            // 加载完成之后，我们还是要赋给route对象，和正常的路由一样，赋给他的component属性
            // 参考正常路由：component: () => import('@/views/edu/subject/list')
          }
        }
        // 路由注册完成之后，进行判断子路由对象中，是否需要注册组件，也就是递归调用
        if (route.children && route.children.length) {
          route.children = filterAsyncRouter(route.children)
        }
        return true
      })
  } catch (e) {
    // 注册如果出现异常，进行打印
    console.log(e)
  }
}

// 定义两个要进行管理的数据
const state = {
  routes: [],
  addRoutes: []
}

// 定义一个设置路由的动作
const mutations = {
  SET_ROUTES: (state, routes) => {
    // 赋值路由要添加的路由
    state.addRoutes = routes
    // 由于我们最开始的时候，就已经注册了一些路由了，比如 /login 等
    // 所以我们需要使用 ES6 语法，引入前面已经创建好的路由对象，import { constantRoutes } from '@/router'
    // router路由文件中的 constantRoutes 数组，就是保存路由对象的，我们引入之后，和我们当前的路由，进行一个链接即可
    // concat() 函数，用于将两个数组，进行拼接，这里拼接完成之后，进行赋值给真正的 routes 数据代理
    state.routes = constantRoutes.concat(routes)
  }
}

// 定义一个动作，用于修改路由
const actions = {
  // 定义动作为异步执行
  async generateRoutes({ commit }) {

    // 调用请求，获取后台菜单栏信息
    const asyncRouter = await getMenu()

    // 创建异步对象，并进行返回，那么当执行动作失败了，可以进行回调
    return new Promise(resolve => {
      // 从后台数据中，获取到返回的导航栏对象
      const tmp = asyncRouter.data.permissionList
      // 调用前面的递归函数，创建路由对应的组件，接收的，就已经创建好组件的路由对象了
      const accessedRoutes = filterAsyncRouter(tmp)
      // 调用设置路由动作，将当前的路由对象，赋值过去
      commit('SET_ROUTES', accessedRoutes)
      // 成功回调执行
      resolve(accessedRoutes)
    })
  }
}

export default {
  namespaced: true,
  state,
  mutations,
  actions
}
